import { Callout } from "nextra-theme-docs";

# Quick Start

GZCTF is distributed as a Docker image, you can deploy a fully functional CTF platform with docker-compose. Please note that this is not the only way to deploy GZCTF, we recommend using Kubernetes to deploy. Please refer to [Deployment](/deployment) for related deployment methods.

<Callout type="warning">

The security and front-end functions (such as operating the clipboard) of GZCTF depend on HTTPS. The deployment method described in this section does not provide HTTPS support, so it is not suitable for production environments. For local testing only.

This document does not cover how to configure HTTPS. Please refer to the configuration and usage of software such as nginx and traefik. Please note that the websocket function of GZCTF may also need to be configured independently. If you encounter problems such as the inability to push competition notifications, please check whether the reverse proxy is configured correctly.

</Callout>

## Installation and configuration

<Callout type="info">

You will need to install Docker and docker-compose to get started with GZCTF. You can find the relevant installation instructions on the [Docker official website](https://docs.docker.com/engine/install/).

</Callout>

1. To prepare for the following configuration, please prepare the following initialization parameters:

   - `GZCTF_ADMIN_PASSWORD`: Initial administrator password, effective when the database is not initialized, needs to be set at the first startup. It should be configured in `compose.yml`.
   - `POSTGRES_PASSWORD`: Database password, needs to be configured in `compose.yml` and `appsettings.json`.
   - `XOR_KEY`: A random string used to encrypt the competition private key, needs to be configured in `appsettings.json`.
   - `PUBLIC_ENTRY`: External access address, can be IP or domain name, needs to be configured in `appsettings.json`, used to provide the address of the problem container for players to access.

2. Save the following content as the `appsettings.json` file, **and fill with your initialization parameters**, please refer to [`appsettings.json` configuration](/config/appsettings) for detailed configuration instructions.

   ```json
   {
     "AllowedHosts": "*",
     "ConnectionStrings": {
       "Database": "Host=db:5432;Database=gzctf;Username=postgres;Password=<Your POSTGRES_PASSWORD>"
     },
     "EmailConfig": {
       "SenderAddress": "",
       "SenderName": "",
       "UserName": "",
       "Password": "",
       "Smtp": {
         "Host": "localhost",
         "Port": 587
       }
     },
     "XorKey": "<Your XOR_KEY>",
     "ContainerProvider": {
       "Type": "Docker", // or "Kubernetes"
       "PortMappingType": "Default", // or "PlatformProxy"
       "EnableTrafficCapture": false,
       "PublicEntry": "<Your PUBLIC_ENTRY>", // or "xxx.xxx.xxx.xxx"
       // optional
       "DockerConfig": {
         "SwarmMode": false,
         "Uri": "unix:///var/run/docker.sock"
       }
     },
     "RequestLogging": false,
     "DisableRateLimit": true,
     "RegistryConfig": {
       "UserName": "",
       "Password": "",
       "ServerAddress": ""
     },
     "CaptchaConfig": {
       "Provider": "None", // or "CloudflareTurnstile" or "GoogleRecaptcha"
       "SiteKey": "<Your SITE_KEY>",
       "SecretKey": "<Your SECRET_KEY>",
       // optional
       "GoogleRecaptcha": {
         "VerifyAPIAddress": "https://www.recaptcha.net/recaptcha/api/siteverify",
         "RecaptchaThreshold": "0.5"
       }
     },
     "ForwardedOptions": {
       "ForwardedHeaders": 5,
       "ForwardLimit": 1,
       "TrustedNetworks": ["192.168.12.0/8"]
     }
   }
   ```

3. Save the following content as the `compose.yml` file, **and replace with your initialization parameters**.

   ```yaml
   services:
     gzctf:
       image: gztime/gzctf:latest
       restart: always
       environment:
         - "GZCTF_ADMIN_PASSWORD=<Your GZCTF_ADMIN_PASSWORD>"
         # choose your backend language `en_US` / `zh_CN` / `ja_JP`
         - "LC_ALL=en_US.UTF-8"
       ports:
         - "80:8080"
       volumes:
         - "./data/files:/app/files"
         - "./appsettings.json:/app/appsettings.json:ro"
         # - "./kube-config.yaml:/app/kube-config.yaml:ro" # this is required for k8s deployment
         - "/var/run/docker.sock:/var/run/docker.sock" # this is required for docker deployment
       depends_on:
         - db

     db:
       image: postgres:alpine
       restart: always
       environment:
         - "POSTGRES_PASSWORD=<Your POSTGRES_PASSWORD>"
       volumes:
         - "./data/db:/var/lib/postgresql/data"
   ```

   <Callout type="info">

   You might encounter network segment conflicts, please refer to `compose.yml` subnet configuration or `/etc/docker/daemon.json` subnet configuration.

   ```yaml
   networks:
     default:
       driver: bridge
       ipam:
         config:
           - subnet: 192.168.12.0/24
   ```

   </Callout>

4. Run `docker compose up -d` to start GZCTF, then you can access GZCTF through the browser.

## Initial administrator

Production environment does not have administrative users by default, you need to set the initial administrator password when starting for the first time by setting the `GZCTF_ADMIN_PASSWORD` environment variable, and log in through the `Admin` account.

You can also manually change the database entry to set a currently registered user as an administrator. After the administrator registration is completed and successfully logged in, enter the selected database table and execute:

```sql
UPDATE "AspNetUsers" SET "Role"=3 WHERE "UserName"='your_admin_user_name';
```

You may need the following commands:

```bash
docker compose exec db psql -U postgres
```

```bash
psql (15.2)
Type "help" for help.

postgres=# \c gzctf
You are now connected to database "gzctf" as user "postgres".
gzctf=# #do your sql query
```

## Use Redis as cache

If you want to use Redis as a cache to get a more seamless version switching and server restart experience, you can add the following content to the above configuration:

1. `compose.yml` file

   ```yaml
   services:
     gzctf:
       # ...
       depends_on:
         - db
         - cache

     cache:
       image: redis:alpine
       restart: always

     db:
       # ...
   ```

2. `appsettings.json` file

   ```json
   {
     "AllowedHosts": "*",
     "ConnectionStrings": {
       // ...
       "RedisCache": "cache:6379,abortConnect=false"
     }
     // ...
   }
   ```

Then restart GZCTF with `docker compose up -d`.

## Container image

GZCTF has been pre-built and packaged as a unified Docker image, you can find the relevant image on [Docker Hub](https://hub.docker.com/r/gztime/gzctf).

Please use the following two container registries to get the image:

```
gztime/gzctf:latest
ghcr.io/gztimewalker/gzctf/gzctf:latest
```

Please use the `develop` image tag for test and development versions.

## Challenges configuration

Challenges configuration and examples can be found in the [GZCTF-Challenges](https://github.com/GZTimeWalker/GZCTF-Challenges) repository.

You can also refer to and learn from the public challenges repository of [W4terCTF 2023](https://github.com/W4terDr0p/W4terCTF-2023). The challenges in this repository try to ensure that the Docker Image is small enough to be quickly deployed during the competition while keeping the challenges working properly.

GZCTF distributes dynamic flags by injecting the `GZCTF_FLAG` environment variable into the container, so please make sure that the text in this environment variable is placed in the appropriate location in the **container initialization script** of the challenge. Please note that this environment variable is initialized when the container is started, not when the container image is built.
